home *** CD-ROM | disk | FTP | other *** search
- Page 60,132
- ;---------------------------------------------------------------
- ; BEGIN LISTING 1
- ;---------------------------------------------------------------
- ;
- ; 286LOAD.ASM Copyright (c) 1991 Robert Collins
- ;
- ; This program demonstrates various aspects of CPU
- ; behavior that become apparent when using LOADALL.
- ;
- ; Test 1: Checks that LOADALL loads all the general-
- ; purpose registers; loads the segment registers
- ; with values that are inconsistant to their
- ; respective descriptor cache registers.
- ;
- ; Test 2: Access extended memory in real mode.
- ;
- ; Test 3: Tests that the Present bit in a descriptor
- ; table can be loaded using LOADALL without
- ; generating exception 11. But when the segment
- ; is accessed, exception 13 is generated.
- ; NOTE: This test should be done in protected
- ; mode, but can be done in real mode. 1) In real
- ; mode, no error code is pushed on the stack
- ; (possibly due to a bug in the CPU). 2) Also
- ; in real mode, when this program is emulated on
- ; a '386, the '386 fails to set the Present bit
- ; when any subsequent segment in loaded. This
- ; latter condition is clearly a bug in the '386.
- ;
- ; This program was written for Microsoft MASM 5.1, and
- ; MS DOS 3.3. This program contains compiler directives
- ; and branching techniques that might not be available
- ; on previous versions of the Macro Assembler, nor in
- ; competitive products. If this program is executed on
- ; any version of DOS prior to 3.3, it will most certainaly
- ; cause the system to crash. No attempt is made in this
- ; program to be compatible with previous versions of DOS,
- ; but compatibility can be done, and is left as an
- ; exercise to the reader.
- ;
- ;---------------------------------------------------------------
-
- ;---------------------------------------------------------------
- ; Compiler directives
- ;---------------------------------------------------------------
- Title LOADALL_286
- .radix 16
- .8086
-
-
- ;---------------------------------------------------------------
- ; Interrupt vector segment
- ;---------------------------------------------------------------
- ABS0 segment at 0
- org 06h*4 ; INT 06h vector
- INT_6 dd ?
-
- org 0467h ; PM Return address
- PM_Ret_off dw ? ; Offset
- PM_Ret_seg dw ? ; Segment
-
- org 800h ; LOADALL table loc'n.
- Loadall_Locn label word
-
- ABS0 ends
-
-
- ;---------------------------------------------------------------
- ; Structure definitions
- ;---------------------------------------------------------------
- Desc_cache STRUC ;; Hidden descriptor cache
- A15_A00 dw ? ;; format.
- A23_A16 db ?
- _Type db ?
- _Limit dw ?
- Desc_cache ENDS
-
-
- Loadall_struc STRUC ;; LOADALL memory image format
- dw 3 dup (0)
- _Msw dw 0
- dw 7 dup (0)
- _Tr dw 0
- _Flags dw 2
- _Ip dw 0
- _Ldt dw 0
- _Ds dw 2222h
- _Ss dw 4444h
- _Cs dw 1111h
- _Es dw 3333h
- _Di dw 6666h
- _Si dw 7777h
- _Bp dw 5555h
- _Sp dw 8888h
- _Bx dw 2222h
- _Dx dw 4444h
- _Cx dw 3333h
- _Ax dw 1111h
- ES_Desc db 00,00,03,93h,0ffh,0ffh
- CS_Desc db 00,00,00,9bh,0ffh,0ffh
- SS_Desc db 00,00,04,93h,0ffh,0ffh
- DS_Desc db 00,00,02,93h,0ffh,0ffh
- Gdt_Desc db 00,00,00,00h,000h,000h
- Ldt_Desc db 00,00,06,82h,088h,000h
- Idt_Desc db 00,00,00,00h,0ffh,003h
- TSS_Desc db 00,00,05,89h,000h,008h
- Loadall_Struc ENDS
-
-
- Descriptor STRUC
- Seg_limit dw ? ; Segment limit
- Base_A15_A00 dw ? ; A00..A15 of base address
- Base_A23_A16 db ? ; A16..A23 of base address
- Access_rights db ? ; Segment access rights
- Limit_A19_A16 db ? ; Granularity, Op-size,
- ; Limit A16..A19
- Base_A31_A24 db ? ; A24..A31 of base address
- Descriptor ENDS
-
-
- INT_Desc STRUC
- IGate_Offset dw ? ; Offset of handler
- CSEG_Sel dw ? ; Code segment selector
- db 0
- db 86h ; 286 interrupt gate=16bit
- ; CS:IP, FLAGS
- Resvd dw 0 ; Reserved=0
- INT_Desc ENDS
-
-
- ;---------------------------------------------------------------
- ; Macro definitions
- ;---------------------------------------------------------------
- FARJMP MACRO destination,selector ; dynamic JMP FAR SEG:OFF
- db 0eah ;; jmp instruction
- dw offset destination ;; offset word
- dw selector ;; segment selector word
- endm
-
-
- IO_DELAY MACRO
- out 0edh,ax
- endm
-
- LOADALL MACRO
- mov cx,ABS0
- mov es,cx
- mov cx,(size Loadall_struc) / 2
- mov si,offset Loadall_tbl
- mov di,800h
- rep movsw
- db 0fh,05
- ENDM
-
- PRINT_STRING MACRO MSG_NAME
- mov ah,9
- mov dx,offset MSG_NAME
- int 21h
- ENDM
- ;--------------------------------------------------------------
-
-
- _DATA SEGMENT PARA PUBLIC 'DATA'
- ;---------------------------------------------------------------
- ; Equates & local variables
- ;---------------------------------------------------------------
- ; Protected mode access rights
- ;---------------------------------------------------------------
- CS_access equ 10011011b
- DS_access equ 10010011b
-
- ;---------------------------------------------------------------
- ; Text equates
- ;---------------------------------------------------------------
- CRLF equ <0dh,0ah>
- CRLF$ equ <CRLF,'$'>
- INT6 equ [bp-4]
-
- ;---------------------------------------------------------------
- ; Conditional compilation. Set USE_386=1 if you plan to execute
- ; this program on a '386 using EMULOAD.
- ;---------------------------------------------------------------
- USE_386 equ 0
-
-
- ;---------------------------------------------------------------
- ; Loadall table(s)
- ;---------------------------------------------------------------
- Loadall_tbl Loadall_struc <>
- Machine_State Loadall_struc <>
-
- ;---------------------------------------------------------------
- ; Global Descriptor Table
- ;---------------------------------------------------------------
- GDT_286 Descriptor <Gdt2_len-1,,,DS_access>
- CSEG2 Descriptor <0ffffh,,,CS_access> ; CS
- DSEG2 Descriptor <0ffffh,,,DS_access> ; DS
- Gdt2_len equ $-Gdt_286
-
- ;---------------------------------------------------------------
- ; Interrupt Descriptor Table
- ;---------------------------------------------------------------
- IDT_286 INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT00
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT01
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT02
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT03
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT04
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT05
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT06
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT07
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT08
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT09
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT0a
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT0b
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT0c
- INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT0d
- IDT2_Len equ $-IDT_286
-
- ;---------------------------------------------------------------
- ; Misc. local variables
- ;---------------------------------------------------------------
- Mem_buffer db 400h dup (0)
- Results dw 0
- i8259_1 db ? ; Status for master device
- i8259_2 db ? ; Status of slave device
-
-
- ;---------------------------------------------------------------
- ; String Messages
- ;---------------------------------------------------------------
- Passed db " PASSED.",CRLF$
- Failed db "--> FAILED <--",CRLF$
- Not_286 db "Not 80286 class computer.",CRLF$
- Rmvd db "LOADALL removed from 80286 mask.",CRLF$
- RFail db "Registers weren't loaded correctly."
- LF db CRLF$
-
- ;---------------------------------------------------------------
- ; I'm doing this wierd string definition technique to limit the
- ; page width to 64 characters.
- ;---------------------------------------------------------------
- Test_1 label word
- db "Test 1: Testing 286 LOADALL instruction: ",24
-
- Test_2 label word
- db "Test 2: Testing extended memory in real mode: ",24
-
- Test_3 label word
- db "Test 3: Testing Present BIT in descriptor: ",24
-
- _DATA ends
-
-
- _TEXT SEGMENT PARA PUBLIC 'CODE'
- ASSUME CS:_TEXT, DS:_DATA, ES:_DATA, SS:STACK
- .286p
- ;---------------------------------------------------------------
- ; A little CS-relative data for the stack pointer. This is
- ; to avoid using other kludge techniques, caused by using
- ; LOADALL, that make using the data segment undesirable.
- ;---------------------------------------------------------------
- Stack_ptr dw 0
- dw 0
-
- ;---------------------------------------------------------------
- LOADALL_286 proc far
- ;---------------------------------------------------------------
- PUSH DS ; Setup the stack to
- XOR AX,AX ; return to DOS
- PUSH AX
-
- MOV AX,_Data
- MOV DS,AX
- MOV ES,AX
-
- ;---------------------------------------------------------------
- ; Check CPU type, and set up a minimal invalid opcode handler
- ; in case LOADALL has been removed from the CPU mask.
- ;---------------------------------------------------------------
- IFE USE_386
- Call CPU_Type ; 286, 386?
- cmp ax,2 ; 286?
- je short @F ; yep
- Print_String LF
- Print_String Not_286
- retf ; go split
-
- @@: enter 4,0 ; create stack frame
- mov word ptr INT6,offset INT6_handler
- mov INT6[2],cs
- call set_INT6_vector ; set our INT6 handler
- ENDIF
-
- cli
- Call Save_State ; Save the current CPU
- Print_String LF ; state
- Print_String Test_1
-
-
- ;---------------------------------------------------------------
- ;
- ; TEST1: Real mode
- ; Test general purpose registers
- ; Test Segment registers
- ; Test Descriptor cache base address
- ;
- ; (1) Setup LOADALL structures, and pointers
- ; (2) Execute LOADALL
- ; (3) Verify results of the test
- ;
- ;---------------------------------------------------------------
- mov ax,cs ; Prepare 24-bit
- mov es,ax ; physical address that
- mov si,0 ; is put in the LOADALL
- call Calc_pm_address ; descriptor cache
- mov Loadall_tbl.CS_Desc.A15_A00,ax ; entry.
- mov Loadall_tbl.CS_Desc.A23_A16,dl
- smsw ax
- mov Loadall_tbl._Msw,ax
- mov Loadall_tbl._Ip,offset Verify_State
- mov word ptr cs:stack_ptr,sp ; save SS:SP
- mov word ptr cs:stack_ptr[2],ss
- LOADALL ; If LOADALL is removed
- nop ; from the CPU mask,
- Print_String failed ; then fall through
- Print_String Rmvd ; to here.
-
- Loadall_RET:
- call Restore_state
-
- IFE USE_386
- call set_INT6_vector ; set our INT6 handler
- leave
- ENDIF
-
- retf
-
- ;---------------------------------------------------------------
- Verify_State: ; Verify that LOADALL worked
- ;---------------------------------------------------------------
- ; This is where we land for the first test of '286 LOADALL.
- ; The purpose of this test is to verify that all the general
- ; purpose registers get loaded correctly. Specifically, we are
- ; testing to verify that all segment registers contain values
- ; that don't correspond to the memory addresses they appear to
- ; be pointing to. In other words, we are checking that the
- ; that the segment registers have one value, while their
- ; associated hidden descriptor cache registers have different
- ; values.
- ;---------------------------------------------------------------
- cmp ax,1111h ; Test AX
- jne @F
- cmp bx,2222h ; Test BX
- jne @F
- cmp cx,3333h ; Test CX
- jne @F
- cmp dx,4444h ; Test DX
- jne @F
- cmp bp,5555h ; Test BP
- jne @F
- cmp di,6666h ; Test DI
- jne @F
- cmp si,7777h ; Test SI
- jne @F
- cmp sp,8888h ; Test SP
- jne short @F
- mov ax,cs ; Test CS
- cmp ax,1111h
- jne short @F
- mov ax,ds ; Test DS
- cmp ax,2222h
- jne short @F
- mov ax,es ; Test ES
- cmp ax,3333h
- jne short @F
- mov ax,ss ; Test SS
- cmp ax,4444h
- jne short @F
- cmp word ptr ds:[0],0202h ; Test DS Desc Cache
- jne short @F
- cmp word ptr es:[0],0303h ; Test ES Desc Cache
- jne short @F
- cmp word ptr ss:[0],0404h ; Test SS Desc Cache
- jne short @F
- mov ax,_Data
- mov ds,ax
- mov es,ax
-
- mov ax,cs:stack_ptr[2]
- mov ss,ax
- mov sp,cs:stack_ptr
- FARJMP <@Test1_Pass>,<seg _Text>
-
- ;---------------------------------------------------------------
- ; Loadall failed the REGISTERs test.
- ;---------------------------------------------------------------
- @@: mov ax,_Data
- mov ds,ax
- mov es,ax
- mov ax,cs:stack_ptr[2]
- mov ss,ax
- mov sp,cs:stack_ptr
- FARJMP <@F>,<seg _Text>
-
- @@: Print_String failed
- Print_String RFail
- jmp loadall_ret
-
- ;---------------------------------------------------------------
- ; LOADALL passed
- ;---------------------------------------------------------------
- @Test1_Pass:
- Print_String passed
-
- ;---------------------------------------------------------------
- ;
- ; TEST2: Access extended memory while in real mode.
- ;
- ; (1) Enable A20
- ; (2) Save contents of extended memory
- ; (3) Write data pattern in extended memory
- ; (4) Set IP & ES descriptor cache pointing to extended memory
- ; (5) LOADALL
- ; (6) Verify results
- ; (7) Restore original data in extended memory
- ;
- ;----------------------------------------------------------------
- Print_String Test_2
- Call Enable_Gate20 ; Enable extended memory
- mov bx,0ffffh ; Point to extended mem.
- mov ds,bx ; as FFFF:0010
- mov si,10h
- mov di,offset Mem_buffer
- mov cx,400h / 2 ; 1k data block to test
- rep movsw ; save extended memory
- mov ax,5aa5h ; test pattern
- mov es,bx ; point to extended mem.
- mov cx,400h / 2
- mov di,10h
- rep stosw ; store pattern in mem.
- mov ax,_data
- mov ds,ax
- mov Loadall_tbl._AX,5aa5h
- mov Loadall_tbl._CX,400h / 2
- mov Loadall_tbl._DI,0h
- mov Loadall_tbl._SP,sp ; save SP
- mov Loadall_tbl._IP,offset @F
- mov Loadall_tbl.ES_Desc.A15_A00,00
- mov Loadall_tbl.ES_Desc.A23_A16,10
- LOADALL
-
- @@: repz scasw ; data match?
- lahf ; get flags
- mov bx,_Data
- mov ds,bx
- mov cx,0ffffh
- mov es,cx
- mov cx,400h / 2
- mov si,offset Mem_buffer
- mov di,10h
- rep movsw ; restore data
- mov es,bx
- mov cx,cs:stack_ptr[2]
- mov ss,cx
- FARJMP <@F>,<seg _Text>
- @@: sahf ; restore flags
- jz @Test2_Pass
- PRINT_STRING failed
- jmp Loadall_RET
-
- @Test2_Pass:
- PRINT_STRING passed
-
- ;---------------------------------------------------------------
- ;
- ; TEST3: Test that the Present bit gets loaded w/out exception,
- ; but when a segment is accessed INT13 get generated.
- ;
- ; If LOADALL works even remotely like we think it does,
- ; then this test will work in REAL MODE! And as this
- ; test was originally programmed, it did! However, I
- ; was doing my testing by emulating '286 LOADALL with
- ; '386 LOADALL, where I could use an ICE for debug
- ; purposes. The code worked on a '286, but failed on a
- ; '386! I found that the '386 fails to clear the
- ; Present bit in the descriptor cache register when a
- ; segment register is loaded in real mode. This is
- ; obviously a bug in the '386. Since the CPU is in a
- ; state that can never be duplicated under any program
- ; control, except by using LOADALL (Present=0), the bug
- ; will never be manifested in any production code. As a
- ; result, I reprogramed this example to use protected
- ; mode so it would work on both the '286 and '386.
- ;
- ; (1) Prepare GDT & IDT descriptor cache registers and
- ; descriptor tables, & segment selectors
- ; (2) Set protected mode bit, clear Present bit, set IP
- ; (3) Save the 8259 masks, set the PM return address, and set
- ; CMOS shutdown=5
- ; (4) LOADALL
- ; (5) Generate the exception
- ; (6) Reset ES to a valid segment selector & save results of
- ; test.
- ; (7) Reset the CPU, restore 8259 masks, inhibit A20 from the
- ; CPU bus, restore segment registers to real mode values.
- ; (8) Verify the results
- ;
- ;---------------------------------------------------------------
- ; Test Present bit: verify that P=0 in a descriptor cache
- ; register will, even in REAL MODE, will generate an exception
- ; 13 when trying to access memory
- ;---------------------------------------------------------------
- Test3: Print_String Test_3
- mov ax,_Data
- mov es,ax
- mov si,0
- call Calc_pm_address
- mov DSEG2.Base_A15_A00,ax
- mov DSEG2.Base_A23_A16,dl
- add ax,offset GDT_286
- adc dl,0
- mov Loadall_tbl.GDT_Desc.A15_A00,ax
- mov Loadall_tbl.GDT_Desc.A23_A16,dl
- mov Loadall_tbl.GDT_Desc._Limit,GDT2_Len-1
- mov si,offset IDT_286
- call Calc_pm_address
- mov Loadall_tbl.IDT_Desc.A15_A00,ax
- mov Loadall_tbl.IDT_Desc.A23_A16,dl
- mov Loadall_tbl.IDT_Desc._Limit,IDT2_Len-1
- mov ax,_TEXT
- mov es,ax
- mov si,0
- call Calc_pm_address
- mov CSEG2.Base_A15_A00,ax
- mov CSEG2.Base_A23_A16,dl
- mov Loadall_tbl._CS,CSEG2-GDT_286
-
- or Loadall_tbl._MSW,1
- and Loadall_tbl.ES_Desc._Type,7fh ; Clear P bit
- mov Loadall_tbl._IP,offset @PM_286 ; Set IP
-
- Call Get_INT_Status ; save PIC masks
- mov ax,offset @RM_286 ; save real mode return
- Call SetPM_RET_addr ; address
- Call Set_shutdown_type ; set shutdown in CMOS
-
- LOADALL
-
- @PM_286:mov al,es:[di][2]
-
- mov ax,DSEG2-GDT_286
- mov es,ax
- mov ES:Results,di
- jmp RESET_CPU
-
- @RM_286:mov ax,cs:stack_ptr[2]
- mov ss,ax
- mov sp,cs:stack_ptr
- mov ax,_Data
- mov ds,ax
- mov es,ax
- call Set_INT_Status
- call Shut_A20
-
- mov di,Results ; If an exception 13 was
- test di,1 ; generated, then the
- jnz @F ; low bit of DI is set
-
-
- Print_String failed ; Test failed
- jmp Loadall_RET
-
- @@: Print_String passed ; Test passed
- jmp Loadall_RET
- LOADALL_286 endp
-
-
- ;---------------------------------------------------------------
- ; Minimal exception 13 handler that points past a 4-byte opcode,
- ; and sets the lowest bit in DI before returning.
- ;---------------------------------------------------------------
- INT13 label word
- push bp
- mov bp,sp
- add word ptr [bp][4],4
- or di,1
- pop bp
- add sp,2
- iret
-
-
- ;---------------------------------------------------------------
- ; Equates & local variables
- ;---------------------------------------------------------------
- ; I/O Ports
- ;---------------------------------------------------------------
- Mstrmsk equ 021h ; 8259 master mask addr
- KBC_CTL equ 060h ; 8042 control port
- KBC_STAT equ 064h ; 8042 status port
- Cmos_index equ 070h ; CMOS address port
- Cmos_data equ 071h ; CMOS data port
- Slv_msk equ 0a1h ; 8259 slave mask addr
-
- ;---------------------------------------------------------------
- ; CMOS RAM
- ;---------------------------------------------------------------
- Shut_down equ 00fh ; CMOS index for shutdwn
- Type5 equ 5 ; Shutdown type-5
-
- ;---------------------------------------------------------------
- ; Keyboard Controller
- ;---------------------------------------------------------------
- inpt_buf_full equ 2 ; Input buffer full
- Shutdown_CMD equ 0feh ; Shutdown CMD for KBC
- enable_bit20 equ 0dfh ; enable A20 command
- disable_bit20 equ 0ddh ; disable A20 command
-
-
- ;---------------------------------------------------------------;
- RESET_CPU:; Resets the CPU by sending a shutdown command to
- ; the keyboard controller.
- ;---------------------------------------------------------------
- ; Input: None
- ; Output: None
- ; Register(s) modified: Doesn't matter, the CPU is reset
- ;---------------------------------------------------------------
- mov al,Shutdown_CMD ; get shutdown command
- out KBC_STAT,al ; send command to shutdown CPU
- cli ; disable interrupts so that
- ; an INT can't come through
- ; before the CPU resets
- hlt ;
-
-
- ;---------------------------------------------------------------;
- ; SETPM_RET_ADDR: Save the real-mode return address @ 40:67
- ; from protected mode.
- ;---------------------------------------------------------------
- ; Input: CS:AX = Return address from PM.
- ; DS = Better darn well have a PM segment selector!
- ; (Or else Kablooie!)
- ; Output: None
- ; Register(s) modified: None
- ;---------------------------------------------------------------
- Setpm_ret_addr proc near
- ;---------------------------------------------------------------
- push dx ; save it
- push ds
- mov dx,ABS0 ;
- mov ds,dx
- ASSUME DS:ABS0
- mov DS:PM_Ret_off,ax
- mov DS:PM_Ret_seg,cs
- ASSUME DS:_DATA
- pop ds
- pop dx
- ret
- Setpm_ret_addr endp
-
-
- ;---------------------------------------------------------------
- ; Get_INT_status: Saves the master and slave mask register
- ; contents from the 8259 interrupt controller.
- ;---------------------------------------------------------------
- ; Input: DS = _DATA SEGMENT
- ; Output: i8259_1 = Status of master device
- ; i8259_2 = Status of slave device
- ; Register(s) modified: None
- ;---------------------------------------------------------------
- Get_int_status proc near
- ;---------------------------------------------------------------
- push ax
- in al,mstrmsk ; get master PIC mask
- mov i8259_1,al
- IO_Delay ; I/O delay
- in al,slv_msk ; get slave PIC mask
- mov i8259_2,al
- pop ax
- ret ; exit
- Get_int_status endp
-
-
- ;---------------------------------------------------------------;
- ; Set_INT_status: Restores the interrupt status of the 8259A
- ; programmable interrupt controller (PIC).
- ;---------------------------------------------------------------
- ; Input: i8259_1 = Status of master device
- ; i8259_2 = Status of slave device
- ; DS = _DATA SEGMENT
- ; Output: None
- ; Register(s) modified: None
- ;---------------------------------------------------------------
- Set_int_status proc near
- ;---------------------------------------------------------------
- pushf ; save interrupt flag
- cli ; we REALLY don't want an int
- ; to come through while we are
- push ax ; reprogramming the PIC masks
- mov al,i8259_1
- out mstrmsk,al ; restore master PIC mask
- IO_Delay ; I/O delay
- mov al,i8259_2
- out slv_msk,al ; restore slave PIC mask
- pop ax
- popf ; restore interrupt flag
- ret ; exit
- Set_int_status endp
-
-
- ;---------------------------------------------------------------
- ; SET_SHUTDOWN_TYPE: Set the processor shutdown type-5 in CMOS.
- ;---------------------------------------------------------------
- ; Input: None
- ; Output: None
- ; Register(s) modified: None
- ;---------------------------------------------------------------
- Set_shutdown_type proc near
- ;---------------------------------------------------------------
- pushf ; save interrupt status
- cli ; disable ints so somebody else
- ; doesn't do this right now
- push ax
- mov al,shut_down ; Set shutdown byte
- out cmos_index,al ; to shut down x05.
- IO_Delay ; I/O delay
- mov al,Type5 ;
- out cmos_data,al ; CMOS data port
- pop ax
- popf
- ret
- set_shutdown_type endp
-
-
- ;---------------------------------------------------------------
- ; Enable_gate20: Turn on A20, and check for errors.
- ;---------------------------------------------------------------
- ; Input: None
- ; Output: CY=ERROR
- ; Register(s) modified: None
- ;---------------------------------------------------------------
- Enable_gate20 proc near
- ;---------------------------------------------------------------
- push ax
- mov ah,enable_bit20 ; gate address bit 20 on
- Call Gate_A20
- or al,al ; command accepted?
- jz A20_OK ; go if yes
- stc ; set error flag
- A20_OK: pop ax
- ret ; exit
- Enable_gate20 endp
-
-
- ;---------------------------------------------------------------
- ; SHUT_A20: Disable A20 from CPU address BUS.
- ;---------------------------------------------------------------
- ; Input: None
- ; Output: CY=ERROR
- ; Register(s) modified: None
- ;---------------------------------------------------------------
- Shut_a20 proc near
- ;---------------------------------------------------------------
- push ax
- mov ah,disable_bit20 ; gate address bit 20 on
- Call Gate_A20
- or al,al ; was command accepted?
- jz A20_Shut ; go if yes
- stc ; set error flag
-
- A20_Shut:
- pop ax
- ret ; exit
- Shut_a20 endp
-
-
- ;---------------------------------------------------------------
- ; GATE_A20: This routine controls a signal which gates address
- ; line 20 (A20). The gate A20 signal is an output of
- ; of the 8042 slave processor (keyboard controller).
- ; A20 should be gated on before entering protected
- ; mode, to allow addressing of the entire 16M address
- ; space of the 80286, or 4G address space of the
- ; 80386 & 80486. It should be gated off after
- ; entering real mode -- from protected mode.
- ;---------------------------------------------------------------
- ; Input: AH = DD ==> A20 gated off (A20 always 0)
- ; AH = DF ==> A20 gated on (CPU controls A20)
- ; Output: AL = 0 ==> Operation successful
- ; AL = 2 ==> Operation failed, 8042 can't accept cmd
- ; Register(s) modified: AX
- ;---------------------------------------------------------------
- Gate_a20 proc near
- ;---------------------------------------------------------------
- pushf ; save interrupt status
- cli ; disable ints while using 8042
- Call Empty_8042 ; insure 8042 input buffer empty
- jnz A20_Fail ; ret: 8042 unable to accept cmd
- IO_Delay ; I/O Delay
- mov al,0D1h ; 8042 cmd to write output port
- out KBC_STAT,al ; output cmd to 8042
- Call Empty_8042 ; wait for 8042 to accept cmd
- jnz A20_Fail ; ret: 8042 unable to accept cmd
- mov al,ah ; 8042 port data
- out KBC_CTL,al ; output port data to 8042
- Call Empty_8042 ; wait for 8042 to port data
- push cx ; save it
- mov cx,14h ;
- @DLY: IO_Delay ; Wait for KBC to execute the
- loop @DLY ; command. (about 25uS)
- pop cx ; restore it
-
- A20_Fail:
- popf ; restore flags
- ret
- Gate_a20 endp
-
-
- ;---------------------------------------------------------------
- ; EMPTY_8042: This routine waits for the 8042 buffer to empty.
- ;---------------------------------------------------------------
- ; Input: None
- ; Output: AL = 0, 8042 input buffer empty: ZF
- ; AL = 2, Time out; 8042 buffer full: NZ
- ; Register(s) modified: AX
- ;---------------------------------------------------------------
- Empty_8042 proc near
- ;---------------------------------------------------------------
- push cx ; save CX
- xor cx,cx ; CX=0: timeout value
-
- Try_KBC:
- IO_Delay ;
- in al,KBC_STAT ; read 8042 status port
- and al,inpt_buf_full; input buffer full flag (D1)
- loopnz Try_KBC ; loop until input buffer empty
- ; or timeout
- pop cx ; restore CX
- ret
- Empty_8042 endp
-
-
- ;---------------------------------------------------------------
- ; CALC_PM_ADDRESS: Calculate 32-bit protected mode address.
- ; Used for building descriptor tables.
- ;---------------------------------------------------------------
- ; Input: ES:SI = Real mode address
- ; Output: DX:AX = 32-bit linear address
- ; Register(s) modified: AX, DX
- ;---------------------------------------------------------------
- Calc_pm_address proc near
- ;---------------------------------------------------------------
- mov ax,es ; point to control block
- xor dh,dh ; clear upper register
- mov dl,ah ; build high byte of 32-bit addr
- shr dl,4 ; use only high nibble from (AX)
- shl ax,4 ; strip high nibble from segment
- add ax,si ; add GDT offset for low word
- adc dx,0 ; adj high byte if CY from low
- ret ; back to calling program
- calc_pm_address endp
-
-
- ;---------------------------------------------------------------
- Save_state proc near ; Save the machine state before
- ; ; LOADALL
- ;---------------------------------------------------------------
- push ax
- push ds
- mov si,0
- mov di,offset Machine_State.ES_Desc
- mov ax,3000h ; ES descriptor
- mov ds,ax
- mov bx,0303h
- movsw
- mov word ptr [si-2],bx
-
- add ax,1000h ; SS descriptor
- add bx,0101h
- mov si,0
- add di,0ah
- mov ds,ax
- movsw
- mov word ptr [si-2],bx
- sub ax,2000h ; DS descriptor
- sub bx,0202h
- mov si,0
- add di,4
- mov ds,ax
- movsw
- mov word ptr [si-2],bx
- pop ds
-
- smsw ax
- mov Machine_State._Msw,ax
- pushf
- pop ax
- mov Machine_State._Flags,ax
- pop ax
- mov Machine_State._DI,di
- mov Machine_State._SI,si
- mov Machine_State._BP,bp
- mov Machine_State._BX,bx
- mov Machine_State._DX,dx
- mov Machine_State._CX,cx
- mov Machine_State._AX,ax
- mov ax,ds
- mov Machine_State._DS,ax
- mov ax,es
- mov Machine_State._ES,ax
- ret
- Save_state endp
-
-
- ;---------------------------------------------------------------
- Restore_state proc near ; Restore the machine state
- ; ; after LOADALL
- ;---------------------------------------------------------------
- mov ax,_data
- mov ds,ax
- mov ax,3000h ; ES
- mov es,ax
- mov si,offset Machine_State.DS_Desc
- mov di,0
- movsw
- add ax,1000h ; SS
- add si,0ah
- mov di,0
- mov es,ax
- movsw
- sub ax,2000h ; DS
- add si,4
- mov di,0
- mov es,ax
- movsw
- mov ax,Machine_State._ES
- mov es,ax
- mov ax,Machine_State._DS
- mov ds,ax
- mov ax,Machine_State._Flags
- push ax
- popf
- mov ax,Machine_State._Msw
- lmsw ax
- mov ax,Machine_State._AX
- mov cx,Machine_State._CX
- mov dx,Machine_State._DX
- mov bx,Machine_State._BX
- mov bp,Machine_State._BP
- mov si,Machine_State._SI
- mov di,Machine_State._DI
- ret
- Restore_State endp
-
-
- IFE USE_386
- ;---------------------------------------------------------------
- ; Include the CPU_TYPE procedure & LOADALL test
- ;---------------------------------------------------------------
- Include CPU_TYPE.ASM
- ENDIF
-
- _text ends
-
-
- stack segment para stack 'stack'
- db 400h dup (0)
- stack ends
-
- end LOADALL_286
-